package com.ubird.astar.core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

public class OpenList {
	private final static Comparator<AStarNode> comparator = new Comparator<AStarNode>() {
		@Override
		public int compare(AStarNode node0, AStarNode node1) {
			return node0.getF() - node1.getF();
		}
	};

	private Table<Integer, Integer, AStarNode> table;
	private List<AStarNode> list;
	/** 标记当node的F值改变，需要重新排序 */
	private boolean dirty = false;

	public OpenList() {
		table = HashBasedTable.create();
		list = new ArrayList<AStarNode>();
	}

	public void clear() {
		table.clear();
		list.clear();
		dirty = false;
	}

	public int size() {
		return table.size();
	}

	public List<AStarNode> values() {
		return list;
	}

	public void add(AStarNode node) {
		if (node == null) {
			throw new IllegalArgumentException();
		}

		table.put(node.getX(), node.getY(), node);
		list.add(node);
		dirty = true;
	}

	public void touchNeighbor(AStarNode neighbor, AStarNode current,
			AStarNode target) {
		AStarNode node = get(neighbor);
		if (node == null) {
			neighbor.calculatorF(current, target);
			add(neighbor);
		} else if (node.getDistinctG(current) < node.getG()) {
			int oldF = node.getF();
			int newF = node.calculatorF(current, target);
			if (oldF != newF) {
				dirty = true;
			}
		}
	}

	public AStarNode get(int x, int y) {
		return table.get(x, y);
	}

	public AStarNode get(AStarNode node) {
		return get(node.getX(), node.getY());
	}

	public AStarNode removeMinFNode() {
		int size = size();
		if (size == 0) {
			return null;
		} else if (size > 1 && dirty) {
			Collections.sort(list, comparator);
			dirty = false;
		}

		return poll();
	}

	private AStarNode poll() {
		AStarNode node = list.remove(0);
		table.remove(node.getX(), node.getY());
		return node;
	}
}
